#!/usr/bin/python
# -*- coding: utf-8 -*-

#THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
#
#Permission is hereby granted, free of charge, to any person obtaining a
#copy of this software and associated documentation files (the "Software"),  
#to deal in the Software without restriction, including without limitation  
#the rights to use, copy, modify, merge, publish, distribute, sublicense,  
#and/or sell copies of the Software, and to permit persons to whom the  
#Software is furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in 
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
#DEALINGS IN THE SOFTWARE.

# library.py
# written by: 
#     João Grilo <joao.grilo@gmail.com>
#     Jan Jokela <jan@devion.org>

__version__ = 0.2
__doc__ = 'Media library'

import os, sys
import mmpython
import engines.database.drivers as drivers
import object
import mappings
import engines.metadata.parser
import base.config.config as config
import utils.debug as debug

if config.get_option('app', 'debug', 'boolean'): DEBUG = True
else: DEBUG = False

class Generic:

    def __init__(self, search_paths, storage_driver='sqlite', database_name='mediadb'):
        """Initializes the class procedures.

        Creates an storage object to interface with. It will use it
        to store and retrieve relevant information about the media
        that the database is aware of.

        """
        storage_drivers = {
            'sqlite':drivers.SQLite,
            'mysql':drivers.MySQL,
            'postgresql':drivers.PostgreSQL,
        }
        self.search_paths = search_paths
        if DEBUG: debug.printd(os.path.join(sys.path[0], database_name))
        if not os.path.exists(os.path.join(sys.path[0], database_name)):
            if DEBUG: debug.printd("Please be patient, craeting database and grabbing album art")
            self.storage_driver = storage_drivers[storage_driver]('host', 'username', 'password')
            self.rebuild_library()
        self.storage_driver = storage_drivers[storage_driver]('host', 'username', 'password')

    def rebuild_library(self):
        """Rebuild the whole media library.

        The method will run recursively through the appointed directory
        to collect all the media files it can process, and add them to
        the database, keeping the records' metadata present for fast
        access and easy cross reference.

        """
        self.storage_driver._rebuild_storage_system()
        # Transverse through the filesystem
        for search_path in self.search_paths:
            for root, directory, files_list in os.walk(search_path):
                # This prevents the case in which the media is on a root directory
                if len(directory) <= 0:
                    directory = ''
                else:
                    directory = os.path.join(*directory)
                # Get the current files' path
                path = os.path.join(root, directory)
                #print path
                #album_art = engines.metadata.parser.Generic()
                for item in files_list:
                    file_path = os.path.join(path, item)
                    # Check first if we can gather any information about the file
                    metadata = mmpython.parse(file_path)
                    if metadata:
                        # Get part of the declared mime type
                        mime_type = metadata.mime.split('/')[0]
                        #print mime_type
                        #print file_path
                        if mime_type == 'audio' or mime_type == 'video' or mime_type == 'image':
                            # Instantiate the correct class based on mime type
                            media_object = mappings.classes[mime_type](file_path)
                            #print media_object
                            # Make sure the media object's metadata is up to date    
                            media_object.update_metadata(metadata)
                            # And, finally, add the information to the database
                            #print media_object
                            try:
                                self.add_media(media_object)
                            except: pass
                            #print 'done'
    def add_path(self, search_path, filter=('audio', 'video', 'image')):
        """
        Adds media objects in given path to the library.
        
        keyword arguments:
        search_path (string) -- path to search for media files
        filter (list) -- is used to specify what mime types to search for
        """
        
        for root, directory, files_list in os.walk(search_path):
            # This prevents the case in which the media is on a root directory
            if len(directory) <= 0:
                directory = ''
            else:
                directory = os.path.join(*directory)         
            # Get the current files' path
            path = os.path.join(root, directory)
            for item in files_list:
                file_path = os.path.join(path, item)
                # Check first if we can gather any information about the file
                metadata = mmpython.parse(file_path)
                if metadata:
                    # Get part of the declared mime type
                    mime_type = metadata.mime.split('/')[0]
                    # Check if our mime type is in the filter
                    if mime_type in filter:
                        # Instantiate the correct class based on mime type
                        media_object = mappings.classes[mime_type](file_path)
                        #print media_object
                        # Make sure the media object's metadata is up to date    
                        media_object.update_metadata(metadata)
                        # And, finally, add the information to the database
                        #print media_object
                        try:
                            self.add_media(media_object)
                        except: pass
                        
    def rem_path(self, path, filter=('audio', 'video', 'image')):
        for mime_type in filter:
            media_objects = self.get_media_files(mime_type, ['uri'])
            for media_object in media_objects:
                for root, directory, files_list in os.walk(path):
                    # This prevents the case in which the media is on a root directory
                    if len(directory) <= 0:
                        directory = ''
                    else:
                        directory = os.path.join(*directory)         
                    # Get the current files' path
                    path = os.path.join(root, directory)
                    for item in files_list:
                        file_path = os.path.join(path, item)      
                        if file_path == media_object.uri:
                            self.rem_media(media_object)

    def add_media(self, media_object):
        """Adds a media object to the library.

        Keyword arguments:
        media_object (media.object.*) -- The object representing the media.

        """
        return self.storage_driver.add_record(media_object.media_type, media_object)

    def rem_media(self, media_object):
        """Removes a file from the library.

        Keyword arguments:
        media_object (media.object.*) -- The object representing the media.

        """
        return self.storage_driver.rem_record(media_object.media_type,
                                              'uri',
                                              media_object.uri)

    def change_media(self, old_media_object, new_media_object):
        """Alters an already present record.

        This method should be called whenever an already existing
        record has its information altered.

        Keyword arguments:
        old_media_object (media.object.*) -- Object representing the old media.
        new_media_object (media.object.*) -- Object containing newer info.

        """
        return self.storage_driver.change_record(old_media_object.media_type,
                                                 old_media_object,
                                                 new_media_object)

    def get_media_files(self, media_type, fields_list=['title']):
        """Returns a list of objects.

        Regarding the criteria specified (which matches the sorting
        ones - ex: name, artist, album, genre, year), it returns a
        list containing the files that match it.

        Keyword arguments:
        media_type (string) -- The type of media to be looked for.
        fields_list (list) -- The criteria that must be matched.

        """
        self.results = []
        i =1
        """x = self.storage_driver.get_records(media_type, fields_list)
        self.results = x"""
        if DEBUG: debug.printd("LIBRARY: media type: " + str(media_type))
        for row in self.storage_driver.get_records(media_type, fields_list):
            if DEBUG: debug.printd("LIBRARY: row id in get_records: " + str(i))
            self.results.append(mappings.classes[media_type](**row))
            if DEBUG: debug.printd("LIBRARY: mappings: " + str(mappings.classes[media_type](**row)))
            i += 1
        if DEBUG: debug.printd("LIBRARY: results: " + str(self.results))
        return self.results